Release 10.1A: OpenEdge Development:
Progress 4GL Handbook


Subtransactions

You separated the Order update and the OrderLine updates out into two separate transactions by moving the end of the DO TRANSACTION block up after the Order block.

To look at what happens if you combine them all again:

  1. Define a new label for the DO TRANSACTION block:
  2. TransBlock: 
      DO TRANSACTION ON ERROR UNDO, LEAVE: 
        FIND ttOrder WHERE ttOrder.TransType = "" NO-ERROR. 
    

  3. Move this block’s END statement back all the way down to the end of the FOR EACH block, then change the UNDO, LEAVE statement to undo and leave that entire block:
  4.      IF bUpdateOline.ExtendedPrice > (ttOline.ExtendedPrice * 1.2) THEN 
         DO: 
            cMessage = cMessage +  
                       "Line " + STRING(OrderLine.LineNum) +  
                 ": Can't increase price by more than 20%." + CHR(10). 
             UNDO TransBlock, LEAVE TransBlock. 
         END.  
       END.   /* END ELSE DO If we updated the OrderLine */ 
      END.       /* END DO FOR EACH ttOline */ 
     END.         /* END DO Transaction */ 
    

Now the transaction structure looks like the diagram in Figure 17–8.

Figure 17–8: Third variation of transaction scope

If there’s an error on any OrderLine, then the whole transaction is backed out, including any change to the Order.

To test this:

  1. Edit one of the fields in the Order, such as the PO, and then make an invalid change to one of its OrderLines.
  2. Click Save. You see an error message.
  3. Click Fetch to refresh the Order.

The changes you made to the Order have been undone along with changes to the OrderLines. (Note that the code isn’t set up to refresh the Order display if the transaction fails. This is an exercise you can do yourself.)

But what if you want to undo a portion of a transaction? Progress supports the capability to do this. If your application has multiple nested blocks, each of which would be a transaction block if it stood on its own, then the outermost block is the transaction and all nested transaction blocks within it become subtransactions. A subtransaction block can be:

If an application error occurs during a subtransaction, all the work done since the beginning of the subtransaction is undone. You can nest subtransactions within other subtransactions. You can use the UNDO statement to programmatically undo a subtransaction.

Note: If a system error occurs, for example from a power outage, then the work done during the entire transaction is undone.

In the sample logic procedure, for example, with the END statement moved to the end, the FOR EACH block is really a subtransaction within the main transaction. An error inside this inner block undoes only the change made in that block. Likewise, if you change the UNDO statement back to UNDO, NEXT, then the Order changes are saved and only the current OrderLine changes are undone, as shown in Figure 17–9.

Figure 17–9: Example subtransaction

Note that a FOR EACH, REPEAT, or procedure block that does not directly contain statements that either modify the database or read records using an EXCLUSIVE-LOCK does not start a transaction on its own. However, if contained inside a transaction block, it does start a subtransaction.


Copyright © 2005 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095